package com.itxiuyixiu.volunteer.service;

import com.itxiuyixiu.entity.enums.ActivityState;
import com.itxiuyixiu.entity.enums.DHUCollage;
import com.itxiuyixiu.entity.mapper.*;
import com.itxiuyixiu.entity.model.*;
import com.itxiuyixiu.tools.security.user.GetUser;
import com.itxiuyixiu.volunteer.common.errors.ServiceException;
import com.itxiuyixiu.volunteer.dto.StudentAuthenticationParam;
import com.itxiuyixiu.volunteer.vo.EnterActivityStateVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Slf4j
@Service
public class UserService {
    @Resource
    private UserReadMapper userReadMapper;
    @Resource
    private StudentWriterMapper studentWriterMapper;
    @Resource
    private StudentReaderMapper studentReaderMapper;
    @Resource
    private TempStudentWriterMapper tempStudentWriterMapper;
    @Resource
    private TempStudentReaderMapper tempStudentReaderMapper;
    @Resource
    private EnterListReaderMapper enterListReaderMapper;
    @Resource
    private EnterListWriterMapper enterListWriterMapper;
    @Resource
    private ActivityReaderMapper activityReaderMapper;
    @Resource
    private OrganizationReaderMapper organizationReaderMapper;
    @Resource
    private ProjectReaderMapper projectReaderMapper;

    /**
     * 学生验证
     *
     * @param dto 用户上传的学生信息
     */
    public void validateStudent(StudentAuthenticationParam dto) {
        User user = getUser();
        if (dto.getAcademy().equals(DHUCollage.OTHER) || dto.getAcademy().equals(DHUCollage.DHU)) {
            throw new ServiceException("上传的学院信息错误，请输入正确的学院信息");
        }
        if (studentReaderMapper.findStudentByUserId(user.getUserId()).isPresent()) {
            throw new ServiceException("您已经通过学生认证了，无法再次认证");
        }
        Optional<TempStudent> tempStudentOptional = tempStudentReaderMapper.findTempStudentByUserId(user.getUserId());
        if (tempStudentOptional.isPresent()) {
            TempStudent tempStudent = tempStudentOptional.get();
            tempStudent.setStudentId(dto.getStudentId());
            tempStudent.setStudentName(dto.getStudentName());
            tempStudent.setStudentContact(dto.getStudentContact());
            tempStudent.setSex(dto.getSex());
            tempStudent.setAcademy(dto.getAcademy());
            tempStudentWriterMapper.modifyTempStudentById(tempStudent);
            log.info("用户" + user.getUsername() + "修改了正在认证的学生信息");
            throw new ServiceException("您已经成功修改正在审核的信息");
        }
        Optional<Student> studentOptional = studentReaderMapper.findStudentByStudentId(dto.getStudentId());
        if (!studentOptional.isPresent()) {
            TempStudent tempStudent = new TempStudent();
            tempStudent.setStudentId(dto.getStudentId());
            tempStudent.setStudentName(dto.getStudentName());
            tempStudent.setStudentContact(dto.getStudentContact());
            tempStudent.setSex(dto.getSex());
            tempStudent.setAcademy(dto.getAcademy());
            tempStudent.setUserId(user.getUserId());
            tempStudentWriterMapper.saveTempStudent(tempStudent);
            log.info("用户" + user.getUsername() + "正在申请学生认证，等待学院审核中");
            throw new ServiceException("请等待学院志愿者组织的审核，假若审核失败，此信息将会被直接删除");
        }
        Student student = studentOptional.get();
        if (!student.getStudentName().equals(dto.getStudentName())) {
            throw new ServiceException("您上传的信息与数据库中的信息不一致。若确认您的信息正确，请联系您所在学院的志愿者组织修改您的信息后再次认证");
        }
        if (student.getUserId() != null) {
            throw new ServiceException("此学生信息已经被他人认证。若确认他人冒用您的信息，请联系您所在学院学院志愿者组织");
        }
        student.setUserId(user.getUserId());
        studentWriterMapper.saveStudent(student);
    }

    /**
     * 查找所有志愿者组织信息
     *
     * @return 志愿者组织信息
     */
    public List<Organization> findAllOrganization() {
        return organizationReaderMapper.findAllOrganization();
    }

    /**
     * 查看指定志愿者信息
     *
     * @param OrgId 志愿者组织编号
     * @return 志愿者组织信息
     */
    public Organization findOrganizationByOrgId(Integer OrgId) {
        Optional<Organization> organizationOptional = organizationReaderMapper.findOrganizationByOrganizationId(OrgId);
        return organizationOptional.orElse(null);
    }

    /**
     * 查询某志愿者组织包含的项目
     *
     * @param OrgId 志愿者组织id
     * @return 所含项目信息
     */
    public Organization findOrganizationWithProjectByOrganizationId(Integer OrgId) {
        return organizationReaderMapper.findOrganizationWithProjectByOrganizationId(OrgId).orElse(null);
    }

    /**
     * 查询志愿者项目信息与组织信息、活动信息
     *
     * @param projectId 志愿者项目id
     * @return 查询志愿者项目信息与组织信息、活动信息
     */
    public Project findProjectWithOrganizationAndActivityByProjectId(Integer projectId) {
        return projectReaderMapper.findProjectWithOrganizationAndActivityByProjectId(projectId).orElse(null);
    }

    /**
     * 查询所有活动信息
     *
     * @return 活动信息
     */
    public List<ActivityView> findAllActivity() {
        return activityReaderMapper.findAllActivityView().stream()
                .filter(e -> e.getActivityState().equals(ActivityState.PASSED) || e.getActivityState().equals(ActivityState.NOT_STARTED) || e.getActivityState().equals(ActivityState.PROCESSING))
                .collect(Collectors.toList());
    }

    /**
     * 查询某志愿者组织包含的所有活动
     *
     * @param OrgId 志愿者组织id
     * @return 所有项目信息
     */
    public Organization findOrganizationWithActivityByOrganizationId(Integer OrgId) {
        return organizationReaderMapper.findOrganizationWithActivityByOrganizationId(OrgId).orElse(null);
    }

    /**
     * 查询指定活动id信息
     *
     * @param activityId 活动id
     * @return 活动信息
     */
    public Activity findActivityWithProjectAndOrganizationByActivityId(Integer activityId) {
        return activityReaderMapper.findActivityWithProjectAndOrganizationByActivityId(activityId).orElseThrow(()->new ServiceException("活动信息不存在"));
    }

    /**
     * 学生参与活动
     *
     * @param activityId 活动id
     */
    @Transactional(rollbackFor = Exception.class)
    public void enterActivity(Integer activityId) {
        Student student = getStudent();
        Optional<Activity> activityOptional = activityReaderMapper.findActivityByActivityId(activityId);
        if (!activityOptional.isPresent()) {
            throw new ServiceException("活动不存在");
        }
        Activity activity = activityOptional.get();
        if (activity.getActivityState().compare(ActivityState.PASSED) < 0 || activity.getActivityState().equals(ActivityState.CANCELED) || activity.getActivityState().equals(ActivityState.FINISHED)) {
            throw new ServiceException("活动处于无法报名状态");
        }
        if (LocalDateTime.now().isAfter(activity.getOutTime())) {
            throw new ServiceException("活动已经停止报名");
        }
        if (enterListReaderMapper.isStudentEnteredActivity(activity.getActivityId(), student.getSId())) {
            throw new ServiceException("您已经参加了活动，不能再次参加");
        }
        if (activity.getNowNumber() >= activity.getMaxNumber()) {
            throw new ServiceException("活动人数已满");
        }
        if (activity.getAcademyLimited() && !activity.getAcademyLimitedList().contains(student.getAcademy().toString())) {
            throw new ServiceException("很抱歉通知您，您不符合活动报名要求（学院限制）");
        }
        enterListWriterMapper.enterActivity(student.getSId(), activity.getActivityId(), activity.getServeHours());
    }

    /**
     * 学生退出活动
     *
     * @param activityId 活动id
     */
    @Transactional(rollbackFor = Exception.class)
    public void exitActivity(Integer activityId) {
        Student student = getStudent();
        Optional<Activity> activityOptional = activityReaderMapper.findActivityByActivityId(activityId);
        if (!activityOptional.isPresent()) {
            throw new ServiceException("活动不存在");
        }
        Activity activity = activityOptional.get();
        Optional<EnterList> enterListOptional = enterListReaderMapper.findEnterListByActivityIdAndSId(activityId, student.getSId());
        if (!enterListOptional.isPresent()) {
            throw new ServiceException("您未报名该活动");
        }
        if (LocalDateTime.now().isAfter(activity.getOutTime())) {
            throw new ServiceException("活动已经截止报名，无法退出，假如有特殊情况请联系活动举办组织");
        }
        enterListWriterMapper.deleteEnterListBySIdAndActivityId(student.getSId(), activityId);
    }

    /**
     * 返回用户报名的活动的状态信息
     *
     * @return 加活动信息
     */
    public List<EnterListView> findEnterActivity() {
        Student student = getStudent();
        return enterListReaderMapper.findAllEnterListViewBySId(student.getSId());
    }

    /**
     * 返回参加某一活动的状态信息
     *
     * @return 加活动信息
     */
    public EnterActivityStateVo findEnterActivityState(int activityId) {
        Student student = getStudent();
        Optional<EnterList> enterListOptional = enterListReaderMapper.findEnterListByActivityIdAndSId(activityId, student.getSId());
        return enterListOptional.map(enterList -> new EnterActivityStateVo(true, enterList.getGmtCreated())).orElseGet(() -> new EnterActivityStateVo(false));
    }

    /**
     * 获取当前用户信息
     *
     * @return 当前用户信息
     */
    private User getUser() {
        return userReadMapper.findUserByUsername(GetUser.getUserName()).orElseThrow(() -> new ServiceException("没有找到用户信息"));
    }

    private Student getStudent() {
        return studentReaderMapper.findStudentByUsername(GetUser.getUserName()).orElseThrow(()->new ServiceException("您尚未通过学生认证，请先进行学生认证"));
    }
}
